var sw = 20, //小方块的宽
    sh = 20, //小方块的高
    tr = 30, //行数
    td = 30; //列数

//创建一个snake实例
var snake = null,
//创建一个food实例
    food = null,
//创建一个game实例
    game = null;

// 方块构造函数
function Square(x, y, classname) {
  //0,0    0,0
  //20,0   1,0
  //40,0   2,0
  this.x = x * sw;
  this.y = y * sh;
  this.class = classname;
  
  this.viewContent = document.createElement('div'); //方块对应的dom元素
  this.viewContent.className = this.class;  //方块的类名
  this.parent = document.getElementById('snakeWrap')  //方块的父级
  // console.log(this.parent);
}

// 创建方块DOM，并添加到父类
Square.prototype.create = function() {
  this.viewContent.style.position = 'absolute';
  this.viewContent.style.width = sw + 'px';
  this.viewContent.style.height = sh + 'px';
  this.viewContent.style.left = this.x + 'px';
  this.viewContent.style.top = this.y + 'px';

  this.parent.appendChild(this.viewContent);
}

// 从父类移除方块
Square.prototype.remove = function() {
  this.parent.removeChild(this.viewContent)
}

// 蛇的构造函数
function Snake() {
  this.head = null; //存储蛇头的信息
  this.tail = null;  //存储蛇尾的信息
  this.pos = [];  //存储蛇身上的每个方块的位置

//存储蛇走的方向，用一个对象来表示
  this.directionNum = {
    left: {
      x: -1,
      y: 0,
      // rotate为css的属性，定义旋转，顺时针为正，逆时针为负
      rotate: 180
    },
    right: {
      x: 1,
      y: 0,
      rotate: 0
    },
    up: {
      x: 0,
      y:-1,
      rotate: -90
    },
    down: {
      x: 0,
      y: 1,
      rotate: 90
    }
  };  
}

// 蛇的初始化函数
Snake.prototype.init = function() {
  //创建蛇头
  var snakeHead = new Square(2, 0, 'snakeHead');
  snakeHead.create();
  this.head = snakeHead; //更新蛇头的位置
  this.pos.push([2, 0]);  //把蛇头的位置存起来

  //创建蛇身体1
  var snakeBody1 = new Square(1, 0, 'snakeBody');
  snakeBody1.create();
  this.pos.push([1, 0]); //存储蛇的body1

  //创建蛇身体2
  var snakeBody2 = new Square(0, 0, 'snakeBody');
  snakeBody2.create();
  this.tail = snakeBody2; //将蛇的body2也存储起来
  this.pos.push([0, 0]);  //存储蛇的body2

  // 形成链表关系
  snakeHead.pre = null;
  snakeHead.next = snakeBody1;
  snakeBody1.pre = snakeHead;
  snakeBody1.next = snakeBody2;
  snakeBody2.pre = snakeBody1;
  snakeBody2.next = null;

  // 给蛇添加方向，默认方向向右
  this.direction = this.directionNum.right;
}

// 获取蛇头的下一个节点,根据下一个节点元素做出蛇的进一步判断
Snake.prototype.getNextPos = function() {
  //蛇头的下一个节点
  var nextPos = [
    this.head.x / sw + this.direction.x,
    this.head.y / sh + this.direction.y
  ]
  //标志是否撞到自己
  var selfCrash = false;
  this.pos.forEach(function(value) {
    if(value[0] === nextPos[0] && value[1] === nextPos[1]) {
      //如果数组中的两个数据都相等，则表示撞到了自己
      selfCrash = true;
    }
  })
  //1、下一步撞到了自己，游戏结束
  if(selfCrash) {
    console.log('撞到自己，游戏结束');
    game.over();
    this.strageties.die.call(this);
    //return可以阻止在符合条件时程序继续向下执行
    return
  }
  //2、下一步撞到了墙，游戏结束
  if(nextPos[0] < 0 || nextPos[1] < 0 || nextPos[0] > td - 1 || nextPos[1] > tr -1) {
    console.log('撞到墙了，游戏结束');
    this.strageties.die.call(this);
    game.over();
    return
  }
  //3、下一步撞到了食物，蛇身长度加一,先判断有没有生成食物，再将生成食物位置与蛇头下一步位置作比较
  if(food && food.pos[0] == nextPos[0] && food.pos[1] == nextPos[1]) {
    console.log('food!');
    this.strageties.eat.call(this);
    createFood();
    game.score++;
    return
  }
  //4、下一步什么也没有，不做任何操作,走
  this.strageties.move.call(this);
}
// strageties对象存储四种根据下一步元素所作出的情况
Snake.prototype.strageties = {
  move: function(format) {  //format参数用于决定要不要删除最后一个蛇尾的元素，当传了这个参数后就表示吃
    //位置的挪动就是在蛇头的位置创建一个新身体，以新身体的位置代替蛇头的位置，新蛇头位置就是下一步的位置，最后去掉尾部的那个元素
    //创建新身体
    var newBody = new Square(this.head.x/sw, this.head.y/sh, 'snakeBody');
    //更新链表关系
    newBody.next = this.head.next;
    newBody.next.pre = newBody;
    newBody.pre = null;
    //移除旧蛇头
    this.head.remove();
    //调用create函数在页面上显示新身体
    newBody.create();

    // 创建新蛇头,新蛇头的位置为之前蛇头的下一步位置
    var newHead = new Square(this.head.x / sw + this.direction.x, this.head.y / sh + this.direction.y, 'snakeHead');
    //更新链表关系
    newHead.next = newBody;
    newHead.pre = null;
    newBody.pre = newHead;
    //调用create在页面上显示新蛇头
    newHead.viewContent.style.transform = 'rotate('+this.direction.rotate+'deg)';
    newHead.create();

    //更新位置数组pos，相当于在数组的头部新加了一个方块
    this.pos.splice(0, 0, [this.head.x / sw + this.direction.x, this.head.y / sh + this.direction.y])
    //更新蛇头的位置
    this.head = newHead;

    // 如果下一步是食物的话蛇尾不用删除
    if(!format) { //如果format为false，就删除尾部元素
      this.tail.remove();
      //更新链表
      this.tail = this.tail.pre;
      //更新pos数组
      this.pos.pop();
    } 

    
  },
  eat: function() {
    //call改变this指向，当传入true时不删除蛇尾的最后一个元素
    this.strageties.move.call(this, true)
  },
  die: function() {
    console.log('die');
  }
}

//创建一个snake实例
snake = new Snake();

//创建食物
function createFood() {
  // 食物小方块的位置为随机坐标
  var x = null;
  var y = null;

  var include = true; //跳出循环的条件，如果include为true则表示生成的食物在蛇身上（需要继续循环）,如果为false则跳出循环
  while(include) {
    x = Math.round(Math.random() * (td - 1));
    y = Math.round(Math.random() * (tr - 1));
    snake.pos.forEach(function(value) {
      if(x != value[0] && y != value[1]) {
        include = false;
      }
    })
  }
  //生成食物
  food = new Square(x, y, 'snakeFood');
  // 存储一下生成食物的坐标，方便与蛇头下一个位置作比较
  food.pos = [x,y];

  var foodDom = document.querySelector('.snakeFood');
  if(foodDom) {
    foodDom.style.left = x * sw + 'px';
    foodDom.style.top = y * sh + 'px';
  }else {
    food.create();
  } 
}
//Game的构造函数
function Game() {
  this.timer = null;
  this.score = 0;
}
Game.prototype.init = function() {
  snake.init();
  createFood();

  //设置蛇的转向
  document.onkeyup = function(ev) {
    if(ev.key == 'ArrowLeft' && snake.direction != snake.directionNum.right) {
      snake.direction = snake.directionNum.left;
    } else if(ev.key == 'ArrowUp' && snake.direction != snake.directionNum.down) {
      snake.direction = snake.directionNum.up;
    } else if(ev.key == 'ArrowRight' && snake.direction != snake.directionNum.left) {
      snake.direction = snake.directionNum.right;
    } else if(ev.key == 'ArrowDown' && snake.direction != snake.directionNum.up) {
      snake.direction = snake.directionNum.down;
    }
  }
  this.start();
}
Game.prototype.start = function() {
  this.timer = setInterval(function() {
    snake.getNextPos();
  }, 200)
}
//暂停游戏
Game.prototype.pause = function() {
  clearInterval(this.timer);
}
//开启游戏
Game.prototype.over = function() {
  clearInterval(this.timer);
  alert('得分为：'+this.score);

  //游戏回到最初始的状态
  var snakeWrap = document.getElementById('snakeWrap');
  snakeWrap.innerHTML = '';
  // 初始化snake和game，相当于删除原来的sanke和game实例
  sanke = new Snake();
  game = new Game();
  var startBtnWrap = document.querySelector('.beginBtn');
  startBtnWrap.style.display = 'block';
}
game = new Game();
//开启游戏
var startBtn = document.querySelector('.beginBtn button');
// 当按开始按钮之后去掉黑色遮罩层
startBtn.onclick = function() {
  startBtn.parentNode.style.display = 'none';
  game.init();
}
//暂停游戏
// var snakeWrap = document.getElementById('snakeWrap');
var pauseBtn = document.querySelector('.pauseBtn button');
snakeWrap.onclick = function() {
  //暂停游戏出现黑色遮罩层
  game.pause();
  pauseBtn.parentNode.style.display = 'block';
}
pauseBtn.onclick = function() {
  // 再次按下暂停按钮时，开启游戏，去掉黑色遮罩层
  game.start();
  pauseBtn.parentNode.style.display = 'none';
}

